package com.lbt.framework.dao;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;

import com.lbt.framework.general.Page;
import com.lbt.framework.general.Paging;
import com.lbt.framework.general.Searching;
import com.lbt.framework.general.Sort;
import com.lbt.framework.general.Sorting;

/**
 * Data access object (DAO) for domain model
 * 
 * @author MyEclipse Persistence Tools
 */
public abstract class BasicDao<T> implements Dao<T> {
	
	@Resource
	public SessionFactory f;
	private Class<T> clazz;
	private String PREFIX;

	public BasicDao(Class<T> clazz) {
		this.clazz = clazz;
		this.PREFIX = clazz.getSimpleName() + "_";
	}

	@Override
	public final int countByExample(T example) {
		return count(getExample(example, null));
	}

	@Override
	public final int countByExample(T example, String searchWord) {
		return count(getExample(example, searchWord));
	}

	@Override
	public final void delete(T entity) {
		f.getCurrentSession().delete(entity);
	}

	@SuppressWarnings("unchecked")
	@Override
	public final T get(Serializable id) {
		return (T) f.getCurrentSession().get(clazz, id);
	}

	@Override
	public final List<T> listByExample(T example) {
		return list(getExample(example, null), null, null).getList();
	}

	@Override
	public final Page<T> listByExample(T example, Paging si) {
		return list(getExample(example, null), null, si);
	}

	@Override
	public final Page<T> listByExample(T example, Paging pi, String searchWord) {
		return list(getExample(example, searchWord), null, (Paging)pi);
	}

	@Override
	public final Page<T> listByExample(T example, Searching si) {
		return list(getExample(example, si.getSearchWord()), (Sorting)si, (Paging)si);
	}

	@Override
	public final List<T> listByExample(T example, Sorting sort) {
		return list(getExample(example, null), sort, null).getList();
	}

	@Override
	public final List<T> listByExample(T example, Sorting sort, String searchWord) {
		return list(getExample(example, searchWord), sort, null).getList();
	}

	@SuppressWarnings("unchecked")
	@Override
	public final T merge(T entity) {
		return (T) f.getCurrentSession().merge(entity);
	}

	@Override
	public final T persist(T entity) {
		f.getCurrentSession().persist(entity);
		return entity;
	}

	@Override
	public final T save(T entity) {
		Serializable ser = f.getCurrentSession().save(entity);
		return get(ser);
	}

	@Override
	public final T saveOrUpdate(T entity) {
		f.getCurrentSession().saveOrUpdate(entity);
		return entity;
	}

	@Override
	public final T update(T entity) {
		f.getCurrentSession().update(entity);
		return entity;
	}

	protected final int count(Criteria c) {
		Object obj = c.setProjection(Projections.rowCount()).list().get(0);
		c.setProjection(null);
		c.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
		return Integer.parseInt(String.valueOf(obj));
	}

	protected final int count(final String queryName, Map<String, Object> params) {
		Query q = getCountQuery(queryName);
		q.setCacheable(true);
		q.setProperties(params);
		return Integer.parseInt(String.valueOf(q.uniqueResult()));
	}

	protected final Criteria createCriteria(Class<T> clazz) {
		Session s = f.getCurrentSession();
		Criteria c = s.createCriteria(clazz);
		c.setCacheable(true);
		return c;
	}

	protected final Criteria createCriteria(Class<T> clazz, String alias) {
		Session s = f.getCurrentSession();
		Criteria c = s.createCriteria(clazz, alias);
		c.setCacheable(true);
		return c;
	}

	protected final int executeUpdate(final String queryName, Map<String, Object> params) {
		Query q = getNamedQuery(queryName);
		q.setProperties(params);
		return q.executeUpdate();
	}

	protected Criteria getExample(T entity, String searchWord) {
		Criteria c = createCriteria(clazz);
		c.setCacheable(true);
		if (null != entity) {
			Example example = Example.create(entity);
			c.add(example);
		}
		return c;
	}
	
	protected final List<T> list(final String queryName, Map<String, Object> params) {
		return list(queryName, params, null, null).getList();
	}
	
	protected final Page<T> list(final String queryName, Map<String, Object> params, Searching si) {
		return list(queryName, params, (Sorting)si, (Paging)si);
	}
	
	protected final List<T> list(Criteria c) {
		return list(c, null, null).getList();
	}

	protected final Page<T> list(Criteria c, Searching si) {
		return list(c, si, si);
	}

	@SuppressWarnings("unchecked")
	protected final T unique(final String queryName, Map<String, Object> params) {
		Query q = getNamedQuery(queryName);
		q.setCacheable(true);
		q.setMaxResults(1);
		q.setProperties(params);
		return (T) q.uniqueResult();
	}

	private Query getCountQuery(final String queryName) {
		
		String queryStr = getNamedQuery(queryName).getQueryString();
		StringBuffer countQueryStr = new StringBuffer("SELECT COUNT(*) ");
		if (queryStr.indexOf("FROM") != -1) {
			countQueryStr.append(queryStr.substring(queryStr.indexOf("FROM")));
		} else {
			countQueryStr.append(queryStr.substring(queryStr.indexOf("from")));
		}
		
		if (queryName.indexOf("Sql") > -1) {
			return f.getCurrentSession().createSQLQuery(countQueryStr.toString());
		} else {
			return f.getCurrentSession().createQuery(countQueryStr.toString());
		}
		
	}

	private Query getNamedQuery(final String queryName) {
		return f.getCurrentSession().getNamedQuery(PREFIX + queryName);
	}

	@SuppressWarnings("unchecked")
	protected final Page<T> list(Criteria c, Sorting si, Paging pi) {
		
		Page<T> page = new Page<T>();
		page.setPaging(pi);
		
		// 页码计算
		if (null != pi && pi.getIsCount()) {
			pi.setTotalResult(count(c));
			
			// 无记录
			if (pi.getTotalResult() == 0) {
				return page;
			}
		}
		
		// 指定排序
		if (null != si) {
			List<Sort> items = si.getSorts();
			if (null != items && items.size() > 0) {
				for (Sort item : items) {
					if (item.isDesc()) {
						c.addOrder(Order.desc(item.getField()));
					} else {
						c.addOrder(Order.asc(item.getField()));
					}
				}

			}
		}
		
		
		// 指定分页
		if (null != pi) {
			c.setFirstResult(pi.getFirstResult());
			c.setMaxResults(pi.getPageSize());
		} else {
			c.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
		}
		
		page.setList(c.list());
		return page;
	}
	
	@SuppressWarnings("unchecked")
	protected final Page<T> list(final String queryName, Map<String, Object> params,  Sorting si, Paging pi) {
		
		Page<T> page = new Page<T>();
		page.setPaging(pi);
		
		// 页码计算
		if (null != pi && pi.getIsCount()) {
			Query cq = getCountQuery(queryName);
			cq.setProperties(params);
			if (queryName.lastIndexOf("Sql") == -1) {
				cq.setCacheable(true);
			}
			int totalResult = Integer.parseInt(String.valueOf(cq.uniqueResult()));
			pi.setTotalResult(totalResult);
			
			// 无记录
			if (totalResult == 0) {
				return page;
			}
		}
		
		
		Session s = f.getCurrentSession();
		Query q = getNamedQuery(queryName);
		
		// 指定排序
		if (null != si) {
			List<Sort> items = si.getSorts();
			if (null != items && items.size() > 0) {
				StringBuffer sortString = new StringBuffer(" ORDER BY ");
				boolean notFirst = false;
				for (Sort item : items) {
					sortString.append((notFirst ? "," : "")
							+ item.getField());
					if (!item.isDesc()) {
						sortString.append(" DESC");
					}
					notFirst = true;
				}
				q = s.createQuery(q.getQueryString() + sortString);

			}
		}
		
		// 指定分页
		if (null != pi) {
			q.setFirstResult(pi.getFirstResult());
			q.setMaxResults(pi.getPageSize());
		}
		
		// 查询
		q.setCacheable(true);
		q.setProperties(params);
		page.setList(q.list());
		return page;
	}

}
